package dnet

import (
	"fmt"
	"io"
	"math"
	"net"
	"strconv"
	"strings"
)

type ErrEvent = func(sender interface{}, err error, errtype int)

const (
	ERR_TYPE_CONNECT  = 3
	ERR_TYPE_IO_WRITE = 2
	ERR_TYPE_IO_RECV  = 1
)

func SplitIPAndPort(addr string) (ip string, port uint16) {
	n := strings.LastIndex(addr, ":")
	if n >= 0 {
		if n > 0 {
			ip = string([]byte(addr)[:n])
		}
		if n < len(addr)-1 {
			str := string([]byte(addr)[n+1:])
			port = uint16(StrToIntDef(str, 0))
		}
	} else {
		ip = addr
	}
	return
}

func StrToIntDef(s string, defval int) int {
	v, err := strconv.ParseInt(s, 10, 32)
	if err != nil {
		return defval
	} else {
		return int(v)
	}
}

func IpV4Bytes(ipv4 string) (rval [4]byte) {
	ipNums := strings.Split(ipv4, ".")
	if len(ipNums) != 4 {
		return rval
	}

	rval[0] = byte(StrToIntDef(ipNums[0], 0))
	rval[1] = byte(StrToIntDef(ipNums[1], 0))
	rval[2] = byte(StrToIntDef(ipNums[2], 0))
	rval[3] = byte(StrToIntDef(ipNums[3], 0))
	return rval
}

func GetFirstMacAsString() string {
	rval, err := GetFirstMac()
	if err != nil {
		return ""
	} else {
		return fmt.Sprintf("%v", rval)
	}
}

func GetFirstMacAsStringEx() string {
	rval, err := GetFirstMacEx()
	if err != nil {
		return ""
	} else {
		return fmt.Sprintf("%v", rval)
	}
}

func GetFirstMac() (net.HardwareAddr, error) {
	// 获取本机的MAC地址
	interfaces, err := net.Interfaces()
	if err != nil {
		return nil, err
	}
	var mac net.HardwareAddr
	for _, inter := range interfaces {
		//fmt.Println(inter.Name)
		mac = inter.HardwareAddr //获取本机MAC地址
		if len(mac) == 0 {
			continue
		}

		if len(mac) < 6 {
			continue
		}

		if mac[0] == 0 && mac[1] == 0 && mac[2] == 0 {
			continue
		}

		//fmt.Printf("idx:%d, MAC:%v, name:%s\n", inter.Index, mac, inter.Name)

		return mac, nil
	}
	return nil, nil
}

func GetFirstMacEx() (net.HardwareAddr, error) {
	// 获取本机的MAC地址
	interfaces, err := net.Interfaces()
	if err != nil {
		return nil, err
	}
	var mac_rval net.HardwareAddr = nil
	var mac_idx int = math.MaxInt32
	for _, inter := range interfaces {
		//fmt.Println(inter.Name)
		mac := inter.HardwareAddr //获取本机MAC地址
		if len(mac) == 0 {
			continue
		}

		if len(mac) < 6 {
			continue
		}

		if mac[0] == 0 && mac[1] == 0 && mac[2] == 0 {
			continue
		}

		if inter.Index < mac_idx {
			mac_idx = inter.Index
			mac_rval = mac
		}

		//fmt.Printf("idx:%d, MAC:%v, name:%s\n", inter.Index, mac, inter.Name)
		// return mac, nil
	}
	return mac_rval, nil
}

func GetAllMacList() string {
	interfaces, err := net.Interfaces()
	if err != nil {
		return err.Error()
	}
	var mac net.HardwareAddr
	rval := ""
	for _, inter := range interfaces {
		//fmt.Println(inter.Name)
		mac = inter.HardwareAddr //获取本机MAC地址
		if len(mac) == 0 {
			continue
		}

		if len(mac) < 6 {
			continue
		}

		if mac[0] == 0 && mac[1] == 0 && mac[2] == 0 {
			continue
		}

		rval += fmt.Sprintf("idx:%d, MAC:%v, name:%s\n", inter.Index, mac, inter.Name)
	}
	return rval
}

func GetAllIpV4List() ([]string, error) {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return nil, err
	}
	rval := make([]string, 0)
	for _, address := range addrs {
		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				rval = append(rval, ipnet.IP.String())
			}
		}
	}
	return rval, nil
}

func DoIoCopy(to io.ReadWriteCloser, from io.ReadWriteCloser, count *int64, onerr_func func(err error, tag int),
	deferfunc func(), buffer_func func() []byte, onrecv func(buf []byte)) {

	if deferfunc != nil {
		defer deferfunc()
	}
	for {
		buf := buffer_func()
		n, err1 := from.Read(buf)
		if err1 != nil {
			if onerr_func != nil {
				onerr_func(fmt.Errorf("read [source] occur err:%s", err1.Error()), 0)
			}
			return
		}
		if count != nil {
			*count += int64(n)
		}
		if onrecv != nil {
			onrecv(buf[:n])
		}
		_, err1 = to.Write(buf[:n])
		if err1 != nil {
			if onerr_func != nil {
				onerr_func(fmt.Errorf("write [dst] occur err:%s", err1.Error()), 1)
			}
			return
		}
	}
}

func DoIoCopyEx(to io.ReadWriteCloser, from io.ReadWriteCloser, count *int64, onerr_func func(err error, tag int),
	deferfunc func(), buffer_func func() []byte, onrecv func(buf []byte), onconvert func(buf []byte) []byte) {

	if deferfunc != nil {
		defer deferfunc()
	}
	for {
		buf := buffer_func()
		if from == nil {
			if onerr_func != nil {
				onerr_func(fmt.Errorf("conn(from) is nil"), 0)
			}
			return
		}
		n, err1 := from.Read(buf)
		if err1 != nil {
			if onerr_func != nil {
				onerr_func(fmt.Errorf("read [source] occur err:%s", err1.Error()), 0)
			}
			return
		}
		if count != nil {
			*count += int64(n)
		}
		if onrecv != nil {
			onrecv(buf[:n])
		}
		newBuf := buf[:n]
		if onconvert != nil {
			newBuf = onconvert(newBuf)
		}

		if len(newBuf) > 0 {
			_, err1 = to.Write(newBuf)
			if err1 != nil {
				if onerr_func != nil {
					onerr_func(fmt.Errorf("write [dst] occur err:%s", err1.Error()), 1)
				}
				return
			}
		}
	}
}

func DoIoCopyFullEvents(to io.ReadWriteCloser, from io.ReadWriteCloser,
	buffer_func func() []byte,
	recvfunc func(r io.ReadWriteCloser, buf []byte) (n int, err error),
	onwrite func(w io.ReadWriteCloser, buf []byte) (n int, err error),
	deferfunc func()) {

	if deferfunc != nil {
		defer deferfunc()
	}
	var n int
	var err1 error
	for {
		buf := buffer_func()
		if from == nil {
			return
		}
		if recvfunc != nil {
			n, err1 = recvfunc(from, buf)
		} else {
			n, err1 = from.Read(buf)
		}
		if err1 != nil {
			return
		}

		newBuf := buf[:n]
		if len(newBuf) > 0 {
			if onwrite != nil {
				_, err1 = onwrite(to, newBuf)
			} else {
				_, err1 = to.Write(newBuf)
			}
			if err1 != nil {
				return
			}
		}
	}
}

func DoIoCopyCycle(makebuf_func func() []byte,
	readfn func(buf []byte) (n int, err error),
	writefn func(buf []byte) (n int, err error),
	deferfunc func()) {

	if deferfunc != nil {
		defer deferfunc()
	}
	if makebuf_func == nil {
		makebuf_func = func() []byte {
			return make([]byte, 1024)
		}
	}
	var n int
	var err1 error
	for {
		buf := makebuf_func()
		n, err1 = readfn(buf)
		if err1 != nil {
			return
		}

		newBuf := buf[:n]
		if len(newBuf) > 0 {
			_, err1 = writefn(newBuf)
			if err1 != nil {
				return
			}
		}
	}
}
